#include "system_calls.h"
#include "sched_mod.h"

//variaveis globais representam as variavais que estarao presentes no kernel
Tabela_processos *ProcessosRT;
Calendario *Eventos;

//main de teste
int main()
{
	int PID, i,j,k;
	
	ProcessosRT = malloc(sizeof(Tabela_processos));
	Eventos = malloc(sizeof(Calendario));

	PID = getpid();
	
	func_init(PID, 0.001, 2);
	
	printf("\nTabela");
	imprime_tabela(ProcessosRT);
	
	for(i=0;i<10;i++)
	{
		func_start_loop(PID);
		printf("\nFazendo outra coisa %d", i);
		for(j=0;j<9999;j++)
		{for(k=0;k<9999;k++){}}
		imprime_calendario(Eventos);
		func_end_loop(PID);
		trata_eventos();
	}
	
	func_term(PID);
	printf("\nTabela");
	imprime_tabela(ProcessosRT);
	printf("\ncalendario");
	imprime_calendario(Eventos);
	
	return 0;
}

//funcao de tratar evento do calendario
void trata_eventos()
{
	struct timeval Tempo;
	struct timespec Tempo_q;
	int PID, Acao;
	double Tempo_atual, Quantum, Tempo_proc;
	bool Fim = false;
	
	while(Fim == false)
	{
		//pega as informacoes do proximo evento do calendario
		proximo_evento(&Tempo_proc, &PID, &Acao, Eventos);
		//pega as informacoes do tempo atual
		gettimeofday(&Tempo, NULL);
		//converte para usec
		Tempo_atual = (Tempo.tv_sec) + (Tempo.tv_usec/1000000.0);
		//pega informacoes de tempo do quantum do escalonador
		sched_rr_get_interval(PID, &Tempo_q);
		//converte
		Quantum = (Tempo_q.tv_sec) + (Tempo_q.tv_nsec/1000000000.0);
		//se o tempo atual + quantum exceder o tempo marcado
		if(Tempo_atual + Quantum > Tempo_proc)
		{
			//remove o evento do calendario
			remove_evento_por_tempo(Tempo_proc, Eventos);
			//se o evento for de tmax, mata o processo
			if(Acao == 2)
			{
				//mata o processo
			}
			//se o evento for de intervalo, aumenta a prioridade do processo
			if(Acao == 1)
			{
				//aumenta prioridade para o maximo
				setpriority(PRIO_PROCESS, PID, -20);
				//desbloqueia o processo
				//COMOFAS????
			}
		}
		else
		{
			//quer dizer que o evento mais proximo esta longe o suficiente
			Fim = true;
		}
	}
}

//funcao de inicializacao
bool func_init(int PID, double Intervalo, double Tmax)
{
	//insere este processo na lista de processos rt
	insere_processo(Intervalo, Tmax, PID, ProcessosRT);
}

//funcao de inicio do loop
void func_start_loop(int PID)
{
	struct timeval Tempo;
	double Tempo_atual, Tempo_evento, Tempo_limite, Intervalo, Tmax;
	
	//remove os eventos anteriores
	while(remove_evento_por_pid(PID, Eventos))
	{}
	//adquire as propriedades do processo
	Intervalo = retorna_intervalo(PID, ProcessosRT);
	Tmax = retorna_tmax(PID, ProcessosRT);
	//pega o tempo do sistema
	gettimeofday(&Tempo, NULL);
	Tempo_atual = (Tempo.tv_sec) + (Tempo.tv_usec/1000000.0);
	//calcula a proxima execucao do processo
	Tempo_evento = Tempo_atual + Intervalo;
	//calcula o tempo maximo de execucao do processo
	Tempo_limite = Tempo_atual + Tmax;
	//criar evento de fim de tmax
	insere_evento(Tempo_limite ,PID, 2, Eventos);
	//criar evento de inicio de loop
	insere_evento(Tempo_evento ,PID, 1, Eventos);
	//aumenta prioridade para o maximo
	setpriority(PRIO_PROCESS, PID, -20);
	
}

//funcao de final do loop
void func_end_loop(int PID)
{
	//remove eventos do tipo 2 do calendario
	while(remove_evento_2_por_pid(PID, Eventos))
	{}
	//diminuir prioridade para a menor possivel
	setpriority(PRIO_PROCESS, PID, 19);
	//bloqueia o processo
	//COMOFAS??????????????????????????
	//chama escalonador
	sched_yield();
}

//funcao de finalzacao de processo
bool func_term(int PID)
{
	//remove a entrada na tabela que contem um processo com PID
	remove_processo(PID, ProcessosRT);
	//remove todos os eventos no calendario que possuem PID
	while(remove_evento_por_pid(PID, Eventos))
	{}
}



/*
Função de inicialização do processo de tempo real: esta função deverá ser chamada por um processo que queira ser tratado como sendo de tempo real, informando ao kernel os valores X e Y de tempo para serem considerados do seu loop. Uma instancia com informações do processo é incluída em uma lista de processos RT do kernel.

Função de início do loop: esta função deverá ser chamada no início do loop crítico que deve ser executado em tempo real. A função irá aumentar a prioridade do processo para o máximo, irá criar um evento de fim de loop X segundos depois do instante atual e um evento de início do próximo loop Y segundos após o tempo atual.

Função de final do loop: esta função é chamada no final do loop crítico do processo, de forma a sinalizar que o loop chegou ao fim. A função irá remover o evento de fim de loop do calendário, diminuir a prioridade do processo para o padrão e fazê-lo dormir, esperando o próximo evento de início de loop já marcado.

Função de finalização do processo: esta função finaliza a participação do processo como tempo real, removendo-o da lista de processos RT e qualquer evento associado a ele.
*/
